Skip to content

chore(ci): add golangci-lint with a strong ruleset + fix CI Go version#61

Merged
AgentWrapper merged 1 commit into
mainfrom
chore/golangci-lint
May 31, 2026
Merged

chore(ci): add golangci-lint with a strong ruleset + fix CI Go version#61
AgentWrapper merged 1 commit into
mainfrom
chore/golangci-lint

Conversation

@AgentWrapper

@AgentWrapper AgentWrapper commented May 31, 2026

Copy link
Copy Markdown
Contributor

What

Introduces golangci-lint to the backend with a strong, tuned ruleset, wires it into CI as a blocking job, and fixes every existing finding so the tree starts at zero.

The config (backend/.golangci.yml) — 27 linters

  • Correctness: errcheck, govet, staticcheck, ineffassign, errorlint, bodyclose, sqlclosecheck, rowserrcheck, nilerr, makezero, gocheckcompilerdirectives, reassign
  • Dead code / boilerplate: unused, unparam, unconvert, wastedassign, copyloopvar, prealloc, dupl
  • Style / quality: revive (incl. exported doc comments on every exported symbol), gocritic, misspell, usestdlibvars, predeclared, nakedret
  • Security: gosec

Tuned for signal over noise: govet/shadow and gocritic hugeParam/rangeValCopy/unnamedResult disabled (idiomatic-Go false positives). Scoped exclusions: sqlc-generated code, tests, gosec/G304 (paths are config/run-file/worktree-derived, not user input), and nilerr in cli/status.go (probe failures are the reported status, not a command error).

CI

  • New blocking lint job (golangci-lint-action, latest binary so it's built with a Go ≥ the module's).
  • Fixed a latent bug: CI pinned Go 1.22 while go.mod declares 1.25. Both jobs now read from go.mod.

Cleanup to reach zero (no behavior change)

84 findings fixed across every lane:

  • errcheck (13): wrap deferred/inline Close()/Remove()/Rollback() with _ =.
  • gosec (5): tighten dir/file perms (07550750, 06440600).
  • unparam (3): drop the always-nil error return from startLifecycle; drop the unused shellPath param (zellij PowerShell) and the always-500 fallbackStatus param (writeProjectError).
  • gocritic (4): \d regex, s != "", switchif, combined appends.
  • revive (~60): doc comments on all exported symbols; rename project.ProjectRowproject.Row (stutter); rename max locals shadowing the builtin.
  • Plus usestdlibvars/staticcheck auto-fixes (http.MethodGet, redundant embedded-field selectors).

golangci-lint run ./...0 issues; go build, go vet, go test ./... all green (21 packages).

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR wires golangci-lint (v2.12.2, 27 linters) into CI as a blocking job and fixes all 84 pre-existing findings to establish a zero-issue baseline. It also corrects a latent CI bug where Go was pinned to 1.22 while go.mod declared 1.25 — both the existing build job and the new lint job now derive the version from go.mod.

  • CI setup: New lint job using golangci-lint-action@v8 with a pinned version; go-version-file replaces the hardcoded Go version in the existing build job.
  • Correctness fixes (no behavior change): Deferred Close/Remove/Rollback errors wrapped with _ =; file/dir permissions tightened from 0o755/0o644 to 0o750/0o600; nil HTTP bodies replaced with http.NoBody.
  • API simplifications: startLifecycle return type collapsed from (*lifecycleStack, error) to *lifecycleStack; writeProjectError drops its always-500 fallbackStatus param; wrapLaunchCommandPowerShell drops its unused shellPath param; ProjectRow renamed to Row to remove package-name stutter.

Confidence Score: 5/5

All changes are mechanical linting fixes with no behavior change; CI infrastructure improvements are well-reasoned and the tree is verified clean at zero findings.

Every code change is a direct, verified fix for a specific linter finding: errcheck wrappers, permission tightening, parameter removals (each confirmed always-same at all call sites), type renaming, and doc comments. The refactors to startLifecycle, writeProjectError, and wrapLaunchCommandPowerShell are all semantically equivalent — the removed parameters were provably unused or constant. No new logic paths are introduced.

No files require special attention. The permission changes (0o755→0o750, 0o644→0o600) are the most operationally visible effect, but they are intentional gosec fixes and affect only the daemon's own data/log directories.

Important Files Changed

Filename Overview
.github/workflows/go.yml Fixes the hardcoded Go 1.22 version to read from go.mod; adds a new blocking lint job using golangci-lint-action@v8 with pinned v2.12.2.
backend/.golangci.yml New golangci-lint v2 config enabling 27 linters with well-reasoned exclusions for generated code, tests, and intentional patterns (nilerr in status.go, G204 for subprocess spawning).
backend/internal/daemon/lifecycle_wiring.go startLifecycle simplified from (*lifecycleStack, error) to *lifecycleStack — the error return was always nil; callers in daemon.go and wiring_test.go updated correctly.
backend/internal/httpd/controllers/projects.go writeProjectError drops the always-500 fallbackStatus param and hardcodes http.StatusInternalServerError — all seven call sites were already passing 500, so behavior is unchanged.
backend/internal/adapters/runtime/zellij/commands.go wrapLaunchCommandPowerShell drops its unused shellPath param — the function never referenced it, reading PATH from cfg.Env instead.
backend/internal/adapters/tracker/github/tracker.go mapStateFromGitHub refactored from a single-case switch to an if/EqualFold — semantically equivalent since stateClosedGH is lowercase; defer resp.Body.Close() wrapped for errcheck.
backend/internal/storage/sqlite/db.go Data directory permission tightened from 0o755 to 0o750 (gosec); writeDB.Close() error explicitly discarded on error paths with _ =.
backend/internal/project/memory_store.go ProjectRow renamed to Row throughout the project package to eliminate the stutter (revive finding); Store interface and all method signatures updated consistently.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[git push or PR] --> B[build job]
    A --> C[lint job]
    B --> B1[setup-go via go.mod]
    B1 --> B2[go build]
    B2 --> B3[go vet]
    B3 --> B4[go test -race]
    C --> C1[setup-go via go.mod]
    C1 --> C2[golangci-lint-action v8 v2.12.2]
    C2 --> C3{27 linters run}
    C3 -->|zero findings| C4[pass]
    C3 -->|any finding| C5[fail - blocks merge]
Loading

Reviews (7): Last reviewed commit: "chore(backend): add golangci-lint with a..." | Re-trigger Greptile

Comment thread .github/workflows/go.yml Outdated
@AgentWrapper AgentWrapper force-pushed the chore/golangci-lint branch 4 times, most recently from 1a495cc to 01e20ce Compare May 31, 2026 22:51
@AgentWrapper

Copy link
Copy Markdown
Contributor Author

@greptile review

@AgentWrapper AgentWrapper force-pushed the chore/golangci-lint branch from 01e20ce to 4d14de0 Compare May 31, 2026 23:09
… tree

Introduces backend/.golangci.yml (27 linters across correctness, dead-code/
boilerplate, style, and security), wires it into CI as a blocking job, and
fixes every finding so the tree starts at zero.

Config:
- 27 linters: errcheck, govet, staticcheck, errorlint, bodyclose,
  sqlclosecheck, rowserrcheck, nilerr, makezero, unused, unparam, unconvert,
  wastedassign, copyloopvar, prealloc, dupl, revive (incl. exported-symbol doc
  comments), gocritic, misspell, usestdlibvars, predeclared, nakedret, gosec, …
- Tuned for signal over noise: govet/shadow and gocritic hugeParam/rangeValCopy/
  unnamedResult disabled (idiomatic-Go false positives); sqlc-generated code and
  tests get scoped exclusions; gosec G304 excluded (paths are config/run-file/
  worktree-derived, not user input); nilerr excluded in cli/status.go (probe
  failures are the reported status, not a command error).

CI:
- New blocking lint job (golangci-lint-action, latest binary for Go-version
  compatibility).
- go-version now read from go.mod (was pinned 1.22 while go.mod declares 1.25).

Cleanup to reach zero (no behavior change):
- errcheck: wrap deferred/inline Close()/Remove()/Rollback() with `_ =`.
- gosec: tighten dir/file perms (0755->0750, 0644->0600).
- unparam: drop always-nil error return from startLifecycle; drop unused
  shellPath param (zellij PowerShell) and always-500 fallbackStatus param
  (writeProjectError).
- gocritic: regexp \d, s != "", switch->if, combined appends.
- revive: doc comments on all exported symbols; rename project.ProjectRow ->
  project.Row (stutter); rename `max` locals shadowing the builtin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AgentWrapper AgentWrapper force-pushed the chore/golangci-lint branch from 4d14de0 to 8df074b Compare May 31, 2026 23:29
@AgentWrapper AgentWrapper merged commit 80f4671 into main May 31, 2026
7 checks passed
@greptile-apps

greptile-apps Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant